#include "LDoble.h"
#include <malloc.h>
#include <string.h>

/*
** Implementacion Primitivas del TDA Lista Doble
*/


/* LD_Crear
@ PRE: LD no creada
@ POS: LD creada
*/
void LD_Crear (TListaDoble *pLD, int TamanioDato)
{
    pLD->Prim = NULL;
    pLD->Cte  = NULL;
    pLD->TamanioDato = TamanioDato;
    }

/* LD_Vacia
@ PRE: LD creada
@ POS: Si la lista esta vacia devuelve TRUE, sino FALSE
*/
int LD_Vacia (TListaDoble LD)
{    if (LD.Prim == NULL)
        {return TRUE;}
     else
        {return FALSE;}
}

/* LD_Vaciar
@ PRE: LD creada
@ POS: Se eliminaron todos los elementos de LD
*/
void LD_Vaciar (TListaDoble *pLD)
{
    TNodoDoble *pNodo, *Sig;
    for (pNodo = pLD->Prim; (pNodo); pNodo=Sig)
    {
        Sig = pNodo->Sig;
        free (pNodo->Elem);
        free (pNodo);
        }
    pLD->Prim = pLD->Cte = NULL;
}


/*
@ PRE: LD creada y no vacia
@ POS: Si M = LD_PRIMERO, el nuevo cte es el primero de la lista
       si M = LD_SIGUIENTE,
       si M = LD_ANTERIOR,
       Si pudo realizar el movimiento devuelve TRUE, sino FALSE
*/
int LD_MoverCte (TListaDoble *pLD, TMovim M )
{
    switch (M)
    {
        case LD_PRIMERO:
            pLD->Cte = pLD->Prim;
            break;
        case LD_SIGUIENTE:
            if (pLD->Cte->Sig == NULL)
                        return FALSE;
            else
                        pLD->Cte = pLD->Cte->Sig;
            break;
        case LD_ANTERIOR:
            if (pLD->Cte->Ant == NULL)
                        return FALSE;
            else
                        pLD->Cte = pLD->Cte->Ant;
            break;
    }
    return TRUE;
}

/*
@ PRE: LD creada
@ POS: Se agrego E a la lista y es el nuevo corriente,
       si M = LD_PRIMERO o la lista esta vacia, se inserto como primero de la lista
       si M = LD_SIGUIENTE, se inserto despues del elemento coriente
       si M = LD_ANTERIOR, se inserto antes del elemento coriente
       Si pudo insertar el elemento devuelve TRUE, sino FALSE
*/
int LD_Insertar (TListaDoble *pLD, TMovim M, void* pE)
{
    TNodoDoble *pNodo = (TNodoDoble*) malloc (sizeof (TNodoDoble));

    if (pNodo)
    {
        pNodo->Elem = malloc (pLD->TamanioDato);
        memcpy (pNodo->Elem, pE, pLD->TamanioDato);
        pNodo->Sig = NULL;

        if ((pLD->Prim == NULL) || (M == LD_PRIMERO)  ||
            ((M == LD_ANTERIOR) && (pLD->Prim == pLD->Cte)))
        {
            pNodo->Sig = pLD->Prim;
            pNodo->Ant = NULL;
						if (pNodo->Sig) pNodo->Sig->Ant=pNodo;
            pLD->Prim  = pNodo;
        }
        else
        {
                if (M == LD_SIGUIENTE)
                {
                            pNodo->Sig = pLD->Cte->Sig;
                            pNodo->Ant = pLD->Cte;
                            pLD->Cte->Sig = pNodo;
                            if (pNodo->Sig) pNodo->Sig->Ant = pNodo;
                }
                else
                {
                            pNodo->Sig = pLD->Cte;
                            pNodo->Ant = pLD->Cte->Ant;
                            pLD->Cte->Ant = pNodo;
                            if (pNodo->Ant) pNodo->Ant->Sig = pNodo;
                }
        }

        pLD->Cte = pNodo;
        return TRUE;
 }
 else
    return FALSE;
}


/*
@ PRE: LD creada y no vacia
@ POS: Se elimino el elemento corriente. El nuevo corriente es el siguiente de eliminado, o el anterior si este era el ultimo
*/
void LD_BorrarCte (TListaDoble *pLD)
{
    TNodoDoble *pAux;

    pAux = pLD->Cte;

    if (pLD->Prim == pLD->Cte)
    {
        pLD->Prim = pLD->Cte->Sig;
        pLD->Cte  = pLD->Prim;
    }
    else
    {
        pAux->Ant->Sig=pLD->Cte->Sig;
        pLD->Cte = pAux->Ant;
    }
    if (pLD->Cte->Sig) pLD->Cte->Sig->Ant=pLD->Cte;
    free(pAux);
}


/*
@ PRE: LD creada y no vacia
@ POS:
*/
void LD_ObtenerCte (TListaDoble LD, void* pE)
{ memcpy (pE, LD.Cte->Elem, LD.TamanioDato); }


/*
@ PRE: LD creada y no vacia
@ POS: se modifico el valor del elemento cte
*/
void LD_ModificarCte (TListaDoble *pLD, void* pE)
{ memcpy (pLD->Cte->Elem, pE, pLD->TamanioDato); }
